/** @file         cmd.c
 *  @brief        命令处理框架的实现
 *  @details      关键字：内核链表、哈希
 *  @date         2020/08/18
 *  @version      v1.1
 *
 *  @attention
 *                在 Linux 上运行, 跨平台需要考虑 移植 申请内存接口
 *                参考来自: jiejieTop@https://github.com/jiejieTop 
 *
 ***********************************************************************************
 *
 *  @par 修改日志:
 *  <table>
 *  <tr><th>Date        <th>Version  <th>Author    <th>Description
 *  <tr><td>2020/05/29  <td>1.0      <td>jiejie    <td>创建初始版本
 *  <tr><td>2020/08/18  <td>1.1      <td>Schips	   <td>重构初始化接口,引入内核链表
 *  <tr><td>2020/08/25  <td>1.2      <td>Schips	   <td>调整接口名，使其更好理解
 *  <tr><td>2020/09/23  <td>1.3      <td>Schips	   <td>新增回调函数 传参接口, 处理函数能够返回执行结果
 *  </table>
 *
 **********************************************************************************
 */
#include "cmd.h"
#include "kernel_list.h"
#define DEFAULT_CMD

// 用于 回调函数执行完毕的调用
static long long  cmd_callback_flag;
void set_cmd_callback_flag(long long flag)
{
    cmd_callback_flag = flag;
}
long long  get_cmd_callback_flag(void)
{
    return cmd_callback_flag;
}

static linknode *cmd_head = NULL;

static inline void * request_mem(size_t size)
{
    return malloc(size);
}
static inline void free_mem(void * prt)
{
    free(prt);
}

static inline linknode * request_list_head(void)
{
	linknode * head;

	head = request_mem(sizeof(linknode));
	if(head == NULL)
	{
		return NULL;
	}

	INIT_LIST_HEAD(&(head->list));

	return head;
}

static inline linknode * new_node(void)
{
	linknode * node;

	node = request_mem(sizeof(linknode));
	if(node == NULL)
	{
		return NULL;
	}
	INIT_LIST_HEAD(&(node->list));

	return node;
}

static inline void insert_node_to_list(linknode * head, linknode * node)
{
    if(!head || !node) return;
	list_add(&node->list, &head->list);
}

static int _char_to_lower(int c)
{
    if ((c >= 'A') && (c <= 'Z'))
        return c + ('a' - 'A');
    return c;
}

static unsigned int _str_hash(const char* str)
{
    int tmp, c = *str;
    unsigned int seed = CMD_HASH; 
    unsigned int hash = 0;

    if(!str) return CMD_HASH;
    
    while(*str) {
        tmp = _char_to_lower(c);
        hash = (hash ^ seed) + tmp;
        str++;
        c = *str;
    }

    return hash;
}

static int _str_match(const char *str, const char *cmd)
{
    int c1, c2;

    if(!str) return -1;
    if(!cmd) return -1;

    do {
        c1 = _char_to_lower(*str++);
        c2 = _char_to_lower(*cmd++);
    } while((c1 == c2) && c1);

    return c1 - c2;
}

#ifdef DEFAULT_CMD
#include <stdio.h>
static void _list_cmd(void)
{
	struct list_head *pos;
	linknode *node;
    if(!cmd_head) return;

	if(list_empty(&cmd_head->list)) 
	{
		return;
	}
    printf("===============\n");
    printf("List all cmd : \n");

	list_for_each(pos, &cmd_head->list)
	{
		node = list_entry(pos, linknode, list);
        printf("%-10s : %s\n", node->cmd.cmd, node->cmd.desc);
	}

    printf("===List Done===\n");

    set_cmd_callback_flag(0);
    return ;
}
#endif

void cmd_init(void)
{
    if(!cmd_head)
    {
        cmd_head = request_list_head();
    }

#ifdef DEFAULT_CMD
    // 内部注册的默认命令。
    REGISTER_CMD("list", _list_cmd, "list all command");
#endif
}

void cmd_deinit(void)
{
	struct list_head *pos, *n;
	linknode *my_list_p;

    if(!cmd_head) return;

	list_for_each_safe(pos, n, &cmd_head->list)
	{
		my_list_p = list_entry(pos, linknode, list);
		free_mem(my_list_p);
	}
	free_mem(cmd_head);
}

long long cmd_parsing(const char *str)
{
	struct list_head *pos;
	linknode *node;
    unsigned int hash = _str_hash(str);

    if(!cmd_head) return CMD_INVALID_ARG;
    
	if(list_empty(&cmd_head->list)) 
	{
		return CMD_NOT_FOUND;
	}

	list_for_each(pos, &cmd_head->list)
	{
		node = list_entry(pos, linknode, list);
        if(hash == node->cmd.hash)
        {
            if(!_str_match(str, node->cmd.cmd))
            {
                set_cmd_callback_flag(CMD_OK); // 默认，允许在回调函数中进行修改
                node->cmd.handler();
                return get_cmd_callback_flag();
            }
        }
	}
    return CMD_NOT_FOUND;
}

void REGISTER_CMD(const char* cmd_str, cmd_handler handler,const char* desc_str)
{
    cmd_t cmd = {
        .cmd     = cmd_str,
        .desc    = desc_str,
        .hash    = _str_hash(cmd_str),
        .handler = handler,
    };
    linknode * node;
    if(!cmd_head)
    {
        cmd_init();
    }
    node = new_node();
    node->cmd = cmd;

    printf("REGISTER_CMD : hash[%08x], key[%10s],\t desc[%20s] \n", node->cmd.hash, node->cmd.cmd, node->cmd.desc);

    insert_node_to_list(cmd_head, node);
    return ;
}

